package timit;

import java.io.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: lahiru
 * Date: 6/12/14
 * Time: 9:56 PM
 * To change this template use File | Settings | File Templates.
 */
public class HUDist {
    private static final int numberOfLayers = 5;
    private static final String hiddenActivationDir = "/home/lahiru/experiments/Speaker-effects/activations/train/";
    private static final String pdfAlignmentsDir = "/home/lahiru/experiments/Speaker-effects/alignments/";
    private static final String saveObjects = "/home/lahiru/experiments/Speaker-effects/objects/train/";
    private static final String listOfSpeakers = "FALK0 FALR0 FBCG1 FBCH0 FBJL0 FCDR1 FCEG0 FCKE0 FCMM0 FDFB0 MCAE0 " +
            "MCAL0 MCHL0 MCSS0 MCTH0 MCTM0 MDBP0 MDCD0 MDHS0 MDLC2";
//    private static final String listOfSpeakers = "FALK0";
    private static final int numberOfHiddenUnits=1024;
    private static final int pdfCount = 117;
    private static final String haVectorDirectory = "/home/lahiru/experiments/Speaker-effects/plots/pdfs/train/hiddenLayer";
    private static final String datDirectory = "/home/lahiru/experiments/Speaker-effects/plots/pdfs/train/";
    private static final String pdfCountFile= "/home/lahiru/experiments/Speaker-effects/docs/pdfcounts.txt";

    public static void main(String[] args) {
        List<String> speakers = (Arrays.asList(listOfSpeakers.split(" ")));
        List<Integer> pcounts = new ArrayList<Integer>(pdfCount);

        try {
            BufferedReader pdfCounts = new BufferedReader(new FileReader(pdfCountFile));
            String pcount;

            for(int j=0; j<pdfCount; j++){  //initialize the pdfCount map
                pcounts.add(j, 0);
            }
            int j=0;
            while ((pcount = pdfCounts.readLine()) != null) {
                 pcounts.add(j, Integer.parseInt(pcount.trim()));
                j++;
            }
            pdfCounts.close();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

//        for(int k=0; k<pdfCount; k++){
//            int val = pcounts.get(k);
//            System.out.println("Pdf id " + k + " count " + val);
//        }




        for (int i = 1; i <= numberOfLayers; i++) {
            System.out.println(" Start processing the layer " + i);

            Map<Integer,Integer> pdfCountMap = new HashMap<Integer, Integer>(pdfCount);
            for(int j=0; j<pdfCount; j++){  //initialize the pdfCount map
                pdfCountMap.put(j,0);
            }

            Map<Integer,List<Double>> huMap = new HashMap<Integer, List<Double>>(numberOfHiddenUnits);
            for(int j=0; j<numberOfHiddenUnits; j++){
                List<Double> tempList = new ArrayList<Double>(pdfCount);
                for(int k=0; k<pdfCount; k++){
                    tempList.add(0.0);
                }
                huMap.put(j,tempList);
            }

            int totalFrameCount = 0;

            for(String spk:speakers){
                int finalFrameCount = 0;

                String ha = hiddenActivationDir + "h" + i + "/activations_" + spk + ".ark";
                String pAlignments = pdfAlignmentsDir + "pdf." + spk +".ark";

//                System.out.println(" Reading the activation file  " + ha + " for the speaker " + spk);
//                System.out.println(" phone labels are in  " + pAlignments + " for the speaker " + spk);

                //Read pdf-alignments line by line, file contains a line per utterance.

                try {
                    BufferedReader phonesBr = new BufferedReader(new FileReader(pAlignments));
                    String line;

                    //Now for each utterance read the hidden activations frame by frame.
                    BufferedReader haBr = new BufferedReader(new FileReader(ha));
                    String line1;

                    int utteranceCount = 0;
                    int frameCount = 0;
                    String frameUtterance = "";
                    String utterance = "";


                    //read a line from the pdf-alignments for each frame in the utterance
                    while ((line = phonesBr.readLine()) != null) {
                        String phoneIds[] = line.split(" ");
                        utterance = phoneIds[0];
                        while ((line1 = haBr.readLine()) != null) {

                            String hArray[] = line1.trim().split(" ");

                            if (hArray.length == 3) {  //starting of an utterance
                                utteranceCount = utteranceCount + 1;
                                frameCount = 0;
                                frameUtterance = hArray[0];

                                String tempArray[] = null;
                                String line2 = "";

                                if (!frameUtterance.equalsIgnoreCase(utterance)) {
                                    System.err.println("The frame utterance " + frameUtterance);
                                    System.err.println("The phone utterance " + utterance);

                                    do {
                                        line2 = haBr.readLine();
                                        tempArray = line2.trim().split(" ");

                                    } while (tempArray.length != 3);

                                    System.err.println("The new frame utterance is " + tempArray[0]);
                                                                                          //write about attributes

                                }

                            } else if (hArray.length == numberOfHiddenUnits) {  //intermediate frame
                                int pdfId = Integer.parseInt(phoneIds[frameCount + 1]);
                                pdfCountMap.put(pdfId, pdfCountMap.get(pdfId)+1);


                                for(int p=0; p<numberOfHiddenUnits;p++){
//                                for(int p=0; p<1;p++){
                                    List<Double> tmpList = huMap.get(p);
                                    tmpList.add(pdfId, tmpList.remove(pdfId)+Double.parseDouble(hArray[p]));
                                    huMap.put(p,tmpList);
                                }

//                                speaker.addFrameStats(Integer.parseInt(phoneIds[frameCount + 1]), hArray);
                                frameCount = frameCount + 1;
                            } else if (hArray.length == numberOfHiddenUnits + 1) {   //last frame of the utterance

                                int pdfId = Integer.parseInt(phoneIds[frameCount + 1]);
                                pdfCountMap.put(pdfId, pdfCountMap.get(pdfId)+1);

                                for(int p=0; p<numberOfHiddenUnits;p++){
//                                for(int p=0; p<1;p++){
                                    List<Double> tmpList = huMap.get(p);
                                    tmpList.add(pdfId, tmpList.remove(pdfId)+Double.parseDouble(hArray[p]));
                                    huMap.put(p,tmpList);
                                }

//                                speaker.addFrameStats(Integer.parseInt(phoneIds[frameCount + 1]), Arrays.copyOfRange(hArray, 0, hArray.length - 1));
                                frameCount = frameCount + 1;
                                finalFrameCount = finalFrameCount + frameCount;
                                break;
                            } else {
                                System.err.println("This is not possible " + hArray.length);
                            }
                        }
                    }
                    haBr.close();
//                    System.out.println(" The utterance count " + utteranceCount);
//                    System.out.println(" The finalFrameCount " + finalFrameCount);
                    totalFrameCount = totalFrameCount + finalFrameCount;

                    phonesBr.close();
                } catch (IOException e) {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                }
            }

//            int totalfcount = 0;
//            for(int k=0; k<pdfCount; k++){
//                int val = pdfCountMap.get(k);
//                System.out.println("Pdf id " + k + " count " + val);
//                totalfcount = totalfcount + val;
//            }
//            System.out.println("Totalfcount " + totalfcount);
//            System.out.println("totalFrameCount " + totalFrameCount);


            try {
                FileWriter fileWriter = new FileWriter(haVectorDirectory + i + ".dat");
                BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

//                bufferedWriter.write("@relation hiddenUnits");
//                bufferedWriter.newLine();
//                bufferedWriter.newLine();
//
//                for (int h = 0; h < pdfCount; h++) {
//                    bufferedWriter.write("@attribute pdf" + h + " numeric\n");
//                }
//                bufferedWriter.newLine();
//                bufferedWriter.newLine();
//
//                bufferedWriter.write("@data\n");
//                bufferedWriter.newLine();
//                bufferedWriter.newLine();
                double totalDistance = 0.0;
                for (int j=0; j<numberOfHiddenUnits; j++){
//                for (int j=0; j<1; j++){

                    FileWriter fileWriter1 = new FileWriter(datDirectory+"h"+i+"/" + j + ".dat");
                    BufferedWriter bufferedWriter1 = new BufferedWriter(fileWriter1);

                    List<Double> activationVector = new ArrayList<Double>(pdfCount);

                    List<Double> tempList = huMap.get(j);
//                    StringBuffer sb = new StringBuffer();
                    for (int p = 0; p < pdfCount; p++) {
                        double value = tempList.get(p);
                        int count = pcounts.get(p);
//                        double finalvalue = (value/count);
                        NumberFormat formatter = new DecimalFormat("###.###############");
                        double intFinalVal = value/count;
                        String finalvalue = formatter.format(intFinalVal);

                        activationVector.add(intFinalVal);
//                        System.out.println("The value " + value);
//                        System.out.println("The pdf id " + p);
//                        System.out.println("The pdf count " + count);
//                        System.out.println("The finalValue " + finalvalue);
                        bufferedWriter1.write(finalvalue+"\n");
//                        if (p == pdfCount - 1) {
//                            sb.append(finalvalue + "\n");
//                        } else {
//                            sb.append(finalvalue + ",");
//                        }
                    }

                    double distance = calKLDistance(activationVector);
                    totalDistance = totalDistance + distance;
                    NumberFormat formatter = new DecimalFormat("###.###############");
                    bufferedWriter.write(formatter.format(distance)+"\n");
                    bufferedWriter1.close();

                }
                System.out.println("The total distance for layer " + i + " is " + totalDistance);
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }


        }


    }

    public static double calKLDistance(List<Double> activationVector) {
        int size = activationVector.size();
        double distance = 0.0;
        int comparisons = 0;
        for(int i=0; i<size; i++){
            for(int j=i+1; j<size; j++){
                double temp = CalculatePhonemeStats.klDivergence(activationVector.get(i), activationVector.get(j)) ;
                String temps = temp +"";
                if (temps.equals("NaN")) {
                    temp = 0.0; //todo change
                }
                distance = distance + temp;
                comparisons = comparisons + 1;
            }
        }
        return (distance/comparisons);  //To change body of created methods use File | Settings | File Templates.
    }
}
